#include <kernel/initcall.h>
#include <kernel/syslog.h>
#include <kernel/bus.h>
#include <drivers/simple.h>
#include <lib/eb_string.h>
#include <mm/mem.h>


static LIST_HEAD(simple_dev);
static LIST_HEAD(simple_drv);


static void simple_device_match_driver(struct simple_device* dev)
{
    int ret = -1;
    struct simple_driver *find_drv = NULL;
    struct list_node *head = &simple_drv;

    list_for_each_entry(find_drv, head, struct simple_driver, entry) {
        
        ret = bus_attach_match_id(find_drv->id_table, dev->compatible);
        if(ret >= 0) {
            dev->driver = find_drv;
            SYSLOG_INFO("simple bus: match successful: match table = [%d], %s", ret, find_drv->id_table[ret].compatible);

            if(find_drv->probe) {
                find_drv->probe(dev);
            }
            return;
        }
    }
}


static void simple_driver_match_device(struct simple_driver* drv)
{
    int ret = -1;
    struct simple_device *find_dev = NULL;
    struct list_node *head = &simple_dev;

    list_for_each_entry(find_dev, head, struct simple_device, entry) {
        
        ret = bus_attach_match_id(drv->id_table, find_dev->compatible);
        if(ret >= 0) {
            find_dev->driver = drv;
            SYSLOG_INFO("simple bus: match successful: match table = [%d], %s", ret, drv->id_table[ret].compatible);

            if(drv->probe) {
                drv->probe(find_dev);
            }
            return;
        }
    }
}


int simple_device_register(struct simple_device *dev)
{
    if(dev->compatible == NULL) {
        SYSLOG_ERROR("compatible of device should not be NULL");
        return -1;
    }
    
    list_add_node_at_tail(&simple_dev, &dev->entry);
    simple_device_match_driver(dev);
    return 0;
}


void simple_device_unregister(struct simple_device *dev)
{
    list_del_node(&dev->entry);
}


int simple_driver_register(struct simple_driver *drv)
{
    if(drv->id_table == NULL && drv->id_table->compatible == NULL) {
        SYSLOG_INFO("compatible of driver should not be NULL");
        return -1;
    }
    
    list_add_node_at_tail(&simple_drv, &drv->entry);
    simple_driver_match_device(drv);

    return 0;
}


void simple_driver_unregister(struct simple_driver *drv)
{
    list_del_node(&drv->entry);
}

